package com.gitee.qdbp.general.common.biz.settings.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.gitee.qdbp.able.beans.KeyString;
import com.gitee.qdbp.able.beans.KeyValue;
import com.gitee.qdbp.able.beans.ParamBuffer;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.general.common.api.settings.model.SystemConfigCoreBean;
import com.gitee.qdbp.general.common.api.settings.service.ISystemDataDictQueryer;
import com.gitee.qdbp.general.common.enums.ConfigDataType;
import com.gitee.qdbp.general.common.enums.ConfigScene;
import com.gitee.qdbp.general.common.enums.ConfigValueType;
import com.gitee.qdbp.tools.utils.VerifyTools;
import libs.fastjson.com.alibaba.fastjson.util.TypeUtils;

/**
 * 系统配置业务处理类
 *
 * @author zhh
 * @version 180812
 */
@Service
@Transactional(readOnly = true)
public class SystemDataDictQueryer extends SystemConfigBaseQueryer implements ISystemDataDictQueryer {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(SystemDataDictQueryer.class);

    public SystemDataDictQueryer() {
        super(ConfigDataType.ITEMS);
    }

    /** 查询枚举类型的选项列表 **/
    @Override
    public List<KeyString> findEnumValues(ConfigScene scene, String tenantCode, String configKey)
            throws ServiceException {
        SystemConfigCoreBean bean = findByKey(scene, tenantCode, configKey);
        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene).append("configKey", configKey);
        return convertConfigBeanToItems(bean, ConfigValueType.enums, KeyString.class, pb);
    }

    /** 查询枚举类型的选项列表中的指定项 **/
    @Override
    public KeyString findEnumValue(ConfigScene scene, String tenantCode, String configKey, String subkey)
            throws ServiceException {
        SystemConfigCoreBean bean = findByKey(scene, tenantCode, configKey);
        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene).append("configKey", configKey).append("subkey", subkey);
        List<KeyString> values = convertConfigBeanToItems(bean, ConfigValueType.enums, KeyString.class, pb);
        if (VerifyTools.isBlank(values)) {
            return null;
        }
        for (KeyString item : values) {
            if (subkey.equals(item.getKey())) {
                return item;
            }
        }
        return null;
    }

    /** 查询对象类型的选项列表 **/
    @Override
    public <T> List<T> findObjectValues(ConfigScene scene, String tenantCode, String configKey, Class<T> clazz)
            throws ServiceException {
        SystemConfigCoreBean bean = findByKey(scene, tenantCode, configKey);
        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene).append("configKey", configKey);
        return convertConfigBeanToItems(bean, ConfigValueType.object, clazz, pb);
    }

    /** 查询对象类型的选项列表的指定项 **/
    @Override
    public <T> T findObjectValue(ConfigScene scene, String tenantCode, String configKey, String subkey, Class<T> clazz)
            throws ServiceException {
        SystemConfigCoreBean bean = findByKey(scene, tenantCode, configKey);

        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene).append("configKey", configKey).append("subkey", subkey);
        return findObjectValue(bean, subkey, clazz, pb);
    }

    private static <T> T findObjectValue(SystemConfigCoreBean bean, String subkey, Class<T> clazz, ParamBuffer pb)
            throws ServiceException {
        if (bean == null) {
            return null;
        }
        if (!ConfigValueType.object.name().equals(bean.getOptions(true).getValueType())) {
            return null;
        }
        // String configKey = bean.getConfigKey();
        String configValue = bean.getConfigValue();
        if (VerifyTools.isBlank(configValue)) {
            return null;
        }

        JSONObject valueMetadata = parseValueMetadata(bean.getOptions(true).getValueMetadata());
        JSONObject valueConfig = valueMetadata == null ? null : valueMetadata.getJSONObject("config");
        String valueField = valueConfig == null ? null : valueConfig.getString("valueField");
        if (VerifyTools.isBlank(valueField)) {
            return null;
        }
        List<JSONObject> items = configValueToItems(configValue, JSONObject.class, pb);
        if (VerifyTools.isBlank(items)) {
            return null;
        }

        JSONObject item = null;
        for (JSONObject i : items) {
            if (subkey.equals(i.get(valueField))) {
                item = i;
            }
        }
        if (item == null) {
            return null;
        }

        if (clazz == KeyString.class || clazz == KeyValue.class) {
            String textField = valueConfig == null ? null : valueConfig.getString("textField");
            if (VerifyTools.isBlank(textField)) {
                textField = valueField;
            }
            return itemToKeyString(item, valueField, textField);
        } else {
            try {
                return TypeUtils.castToJavaBean(item, clazz);
            } catch (JSONException e) {
                log.error("Parse json error, {}, configValue={}", pb, configValue, e);
                throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e);
            }
        }
    }

    /** 查询枚举类型的选项列表 **/
    @Override
    public Map<String, List<KeyString>> listEnumValues(ConfigScene scene, String tenantCode, List<String> configKeys)
            throws ServiceException {

        Map<String, SystemConfigCoreBean> map = listByKeys(scene, tenantCode, configKeys);
        if (map == null) {
            return null;
        }
        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene);
        return parseConfigValuesToMap(map.values(), ConfigValueType.enums, KeyString.class, pb);
    }

    /** 查询对象类型的选项列表 **/
    @Override
    public <T> Map<String, List<T>> listObjectValues(ConfigScene scene, String tenantCode, List<String> configKeys,
            Class<T> clazz) throws ServiceException {
        Map<String, SystemConfigCoreBean> map = listByKeys(scene, tenantCode, configKeys);
        if (map == null) {
            return null;
        }
        ParamBuffer pb = ParamBuffer.newLogBuffer();
        pb.append("scene", scene).append("tenantCode", scene);
        return parseConfigValuesToMap(map.values(), ConfigValueType.object, clazz, pb);
    }

    @SuppressWarnings("unchecked")
    private static <T> T itemToKeyString(JSONObject item, String valueField, String textField) {
        KeyString result = new KeyString();
        result.setKey(item.getString(valueField));
        result.setValue(item.getString(textField));
        return (T) result;
    }

    private static <T> List<T> configValueToItems(String configValue, Class<T> clazz, ParamBuffer pb) {
        try {
            TypeReference<ObjectValues<T>> reference = new TypeReference<ObjectValues<T>>(clazz) {
            };
            ObjectValues<T> temp = JSON.parseObject(configValue, reference.getType());
            return temp.getItems();
        } catch (JSONException e) {
            log.error("Parse json error, {}, configValue={}", pb, configValue, e);
            throw new ServiceException(ResultCode.SERVER_INNER_ERROR, e);
        }
    }

    private static <T> List<T> configValueToKeyStringList(String configValue, Object valueMetadata, ParamBuffer pb) {
        JSONObject valueMetadataJson = parseValueMetadata(valueMetadata);
        JSONObject valueConfig = valueMetadata == null ? null : valueMetadataJson.getJSONObject("config");
        String valueField = valueConfig == null ? null : valueConfig.getString("valueField");
        if (VerifyTools.isBlank(valueField)) {
            return null;
        }
        String textField = valueConfig == null ? null : valueConfig.getString("textField");
        if (VerifyTools.isBlank(textField)) {
            textField = valueField;
        }
        List<JSONObject> items = configValueToItems(configValue, JSONObject.class, pb);
        if (VerifyTools.isBlank(items)) {
            return null;
        }

        List<T> results = new ArrayList<>();
        for (JSONObject i : items) {
            results.add(itemToKeyString(i, valueField, textField));
        }
        return results;
    }

    private static <T> List<T> convertConfigBeanToItems(SystemConfigCoreBean bean, ConfigValueType valueType,
            Class<T> clazz, ParamBuffer pb) throws ServiceException {
        if (bean == null) {
            return null;
        }
        if (!valueType.name().equals(bean.getOptions(true).getValueType())) {
            return null;
        }
        String configValue = bean.getConfigValue();
        if (VerifyTools.isBlank(configValue)) {
            return null;
        }

        if (valueType == ConfigValueType.object && (clazz == KeyString.class || clazz == KeyValue.class)) {
            return configValueToKeyStringList(configValue, bean.getOptions(true).getValueMetadata(), pb);
        } else {
            return configValueToItems(configValue, clazz, pb);
        }
    }

    private static <T> Map<String, List<T>> parseConfigValuesToMap(Collection<SystemConfigCoreBean> values,
            ConfigValueType valueType, Class<T> clazz, ParamBuffer pb) throws ServiceException {

        Map<String, List<T>> result = new HashMap<>();
        for (SystemConfigCoreBean bean : values) {
            if (valueType.name().equals(bean.getOptions(true).getValueType())) {
                ParamBuffer npb = pb.clone().append("configKey", bean.getConfigKey());
                result.put(bean.getConfigValue(), convertConfigBeanToItems(bean, valueType, clazz, npb));
            }
        }
        return result;
    }

    private static JSONObject parseValueMetadata(Object valueMetadata) {
        if (valueMetadata instanceof String) {
            return JSONObject.parseObject((String) valueMetadata);
        } else {
            return TypeUtils.castToJavaBean(valueMetadata, JSONObject.class);
        }
    }

    protected static class ObjectValues<T> {

        private List<T> items;

        public List<T> getItems() {
            return items;
        }

        public void setItems(List<T> items) {
            this.items = items;
        }
    }
}
